package com.tceasy.gateway.util;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class SignUtil {
	private static final Logger logger=LoggerFactory.getLogger(SignUtil.class);


    /**
     * 根据反馈回来的信息，生成签名结果
     * @param params 通知返回来的参数数组
     * @return 生成的签名结果
     */
    public static void verifyRSASign(Map<String, String> params,String publicKey) {
        String encode=params.get("charset");//字符集
        String sign=params.get("sign");
        //获取待签名字符串
        String preSignStr = getSignStr(params);
        //暂时固定为RSA签名
        boolean result= RSA.verify(preSignStr, sign, publicKey,encode);
        if(!result){
            throw new RuntimeException("验签失败");
        }
    }

    /**
     * 根据反馈回来的信息，生成签名结果
     * @param params 通知返回来的参数数组
     * @param key md5key
     * @return 生成的签名结果
     */
    public static void verifyMd5Sign(Map<String, String> params,String key) {
        String sign=params.get("sign");
        String encode=params.get("charset");//字符集
        //md5生成签名
        String mySign = md5Sign(params,key,encode);
        if(!StringUtils.equalsIgnoreCase(sign,mySign)){
            throw new RuntimeException("验签失败");
        }
    }

    /**
     * 用RSA签名
     * @param content 参数字符串 a=a&b=b&c=c的形式
     * @param privateKey 私钥
     * @param charset 字符集
     * @return 签名后的字符串，后边加上了sign和sign_type
     */
    public static String rsaSign(String content,String privateKey,String charset){
        //生成签名
        String sign= RSA.sign(content, privateKey, charset);
        try {
            // 仅需对sign 做URL编码
            return URLEncoder.encode(sign, charset);
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage());
        }
        return null;
    }

	/**
	 * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
	 * 待签名字符串直接拼接秘钥
	 */
	public static String md5Sign(Map<String, String> params,String key,String encode) {
		String signStr=getSignStr(params)+key;//待签名字符串
		String sign = Md5ConverterUtil.MD5Encode(signStr,encode);
		logger.info("创建Md5签名，待签名字符串：{},sign:{}",signStr,sign);
		return sign;
	}
	
    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * 空值、sign和sign_type不参与签名
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String getSignStr(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        StringBuilder sb=new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if(StringUtils.isBlank(value)||key.equalsIgnoreCase("sign")||key.equalsIgnoreCase("signType")){
                continue;
            }
            sb.append(key).append("=").append(value).append("&");
        }
        sb.deleteCharAt(sb.lastIndexOf("&"));
        return sb.toString();
    }
}
